using System;
using System.Text;
using System.Xml;
using System.Security.Cryptography;

[Serializable]
public struct ElGamalParameters {
    public byte[] P;
    public byte[] G;
    public byte[] Y;
    [NonSerialized] public byte[] X;		
}

public abstract class ElGamal : AsymmetricAlgorithm {

    public abstract  ElGamalParameters ExportParameters(bool p_include_private_params);
    public abstract  void ImportParameters(ElGamalParameters p_parameters);

    public abstract byte[] EncryptData(byte[] p_data);    
    public abstract byte[] DecryptData(byte[] p_data);
    public abstract byte[] Sign(byte[] p_hashcode);
    public abstract bool VerifySignature(byte[] p_hashcode, byte[] p_signature);


    public override string ToXmlString(bool p_include_private) {
        ElGamalParameters x_params = ExportParameters(p_include_private);
        // create a new string builder
        StringBuilder x_sb = new StringBuilder();
        // add the header
        x_sb.Append("<ElGamalKeyValue>");
        // add the public elements from the parameters
        x_sb.Append("<P>" + Convert.ToBase64String(x_params.P) + "</P>");
        x_sb.Append("<G>" + Convert.ToBase64String(x_params.G) + "</G>");
        x_sb.Append("<Y>" + Convert.ToBase64String(x_params.Y) + "</Y>");
        if (p_include_private) {
            // we need to include X, which is the part of private key
            x_sb.Append("<X>" + Convert.ToBase64String(x_params.X) + "</X>");
        }
        // add the final element
        x_sb.Append("</ElGamalKeyValue>");
        return x_sb.ToString();
    }

    public override void FromXmlString(String p_string) {
        // create the params that we will use as the result
        ElGamalParameters x_params = new ElGamalParameters();
        // create a text reader using a string reader
        XmlTextReader x_reader = new XmlTextReader(new System.IO.StringReader(p_string));
        
        // run through the elements in the xml string
        while (x_reader.Read()) {
            // we are only interested in processing start nodes
            if (true || x_reader.IsStartElement()) {
                switch (x_reader.Name) {
                    case "P":
                        // set the value for P
                        x_params.P = Convert.FromBase64String(x_reader.ReadString());
                        break;
                    case "G":
                        // set the value for G
                        x_params.G = Convert.FromBase64String(x_reader.ReadString());
                        break;
                    case "Y":
                        // set the value for Y
                        x_params.Y = Convert.FromBase64String(x_reader.ReadString());
                        break;
                    case "X":
                        // set the value for X (this would not be found in a string
                        // that was generated by excluding the private elements.
                        x_params.X = Convert.FromBase64String(x_reader.ReadString());
                        break;
                }
            }
        }
        // Import the result
        ImportParameters(x_params);
    }
}
